/*!
//      
//      \file	k2k_IO.c
//      
//      \author	Copyright 2010 Valentina Vuksic <vuksv1@bfh.ch>, Beat Liechti <liecb2@bfh.ch>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.
//      
//      
//      \brief		CAS-EBX-03 Projektarbeit 
//      			Valentina Vuksic (VUKSV1), Beat Liechti (LIECB2)
//      			IO ADT for the k2k (Kaffee2000) application
//      \version	1.0
//      \date		2010-04-06
//      \remark		Last Modifications:
//      \remark  	v1.0, VUKSV1/LIECB2, 2010-04-10 Initial release
//
*/

#include "k2k_IO.h"

/* -- defines --------------------------------------------------------*/

#define DEV_DISPLAY		"/dev/c2display"
#define DEV_BUTTONS		"/dev/c2buttons"

/* -- ADT functions --------------------------------------------------*/

/*!
//
// Creates IO ADT "object"
// 
// \return pointer to the IO ADT
//
*/
k2k_IO* k2k_IO_Create()
{
	k2k_IO *IO = NULL;
	IO = malloc(sizeof(k2k_IO));
	if (IO != NULL)
	{
#ifdef X86	
		/*! create board specific IO structure */
		IO->x86IO = k2k_X86IO_Create(IO);
		IO->err = (IO->x86IO == NULL ? k2k_IO_ERR_CREATE_X86IO : k2k_IO_ERR_SUCCESS);
#else		
		IO->fd_display = 0;
		IO->fd_button = 0;
		/*! open display/LED device */
		if ((IO->fd_display = open(DEV_DISPLAY, O_RDWR)) <= 0)
		{
			IO->err = k2k_IO_ERR_OPEN_DEV_DISPLAY_FAILED;
		}
		/*! open button/switch device */
		//else if ((IO->fd_button = open("/dev/c2buttons", O_RDWR | O_NONBLOCK)) <= 0)
		else if ((IO->fd_button = open(DEV_BUTTONS, O_RDWR)) <= 0)
		{			
			IO->err = k2k_IO_ERR_OPEN_DEV_BUTTON_FAILED;
		}
		else
		{
			/*! clear button buffer */
			write(IO->fd_button, NULL, 0);
			IO->err = k2k_IO_ERR_SUCCESS;
		}
#endif		
	}
	return IO;
}

/*!
//
// Releases IO ADT "object"
// 
// \param pStack is the pointer to the stack 
// 
// \return noting
//
*/
void k2k_IO_Release(k2k_IO *IO)
{
	if (IO != NULL)
	{		
#ifdef X86		
		if (IO->x86IO != NULL)
		{
			/*! release board specific IO structure */
			k2k_X86IO_Release(IO->x86IO);
			IO->x86IO = NULL;
		}
#else
		if (IO->fd_display > 0)
		{
			close(IO->fd_display);
		}
		if (IO->fd_button > 0)
		{
			close(IO->fd_button);
		}		
#endif		
		/*! release memory */
		free(IO);	
	}
}

/*!
//
// Write a pattern to the LEDs
//
// \param IO is the pointer to the IO structure
// \param pattern is the bit map of the pattern
// 
// \return nothing
//
*/
void k2k_IO_WriteLed(k2k_IO *IO, UINT8 pattern)
{
#ifdef X86
	k2k_X86IO_WriteLed(IO->x86IO, pattern);
#else	
	write(IO->fd_display, &pattern, sizeof(pattern));	
#endif
}

/*!
//
// Read current LED status
//
// \param IO is the pointer to the IO structure
// 
// \return bit map of the pattern
//
*/
UINT8 k2k_IO_ReadLed(k2k_IO *IO)
{
#ifdef X86
	return k2k_X86IO_ReadLed(IO->x86IO);
#else	
	UINT8 currentPattern;
	if (read(IO->fd_display, &currentPattern, sizeof(currentPattern)) != sizeof(currentPattern))
	{
		currentPattern = 0;
	}
	return currentPattern;
#endif
}

/*!
//
// Create event from the values of the switches
// 
// \param IO is the pointer to the IO structure
//
// \return k2k_Event where EVENT_MAX means that no event has happened
//
*/
k2k_Event k2k_IO_GetEvent(k2k_IO *IO)
{	
	/*! return value EVENT_MAX to signal no event */
	int button = EVENT_MAX;
	k2k_Event event = EVENT_MAX;	
#ifdef X86		
	button = k2k_X86IO_ReadButton(IO->x86IO);	
#else	
	ssize_t size = read(IO->fd_button, &button, sizeof(button));
	if (size != sizeof(button))
	{
		button = EVENT_MAX;
	}	
#endif	
	if (button >= EVENT_S0 && button <= EVENT_MAX)
	{
		event = button;
	}
	return event;
}

/*!
//
// Set the LEDs according to the state
//
// \param IO is the pointer to the IO structure
// \param currentState is the current state
// 
// \return nothing
//
*/
void k2k_IO_SetLeds(k2k_IO *IO, k2k_State currentState)
{
	/*! read current LED pattern */
	UINT8 currentPattern;
#ifdef X86
	currentPattern = k2k_X86IO_ReadLed(IO->x86IO);	
#else 
	currentPattern = k2k_IO_ReadLed(IO);
#endif	
	UINT8 newPattern = 0;
	
	switch (currentState)
	{
		case STATE_OFF:
			newPattern = 0;
			break;
		case STATE_RDY1:
			newPattern = LED_01;
			break;
		case STATE_RDY2:
			newPattern = LED_01 | LED_05;
			break;
		case STATE_RSTR:
			newPattern = LED_02 | currentPattern;
			break;
		case STATE_ESPR:
			newPattern = LED_03 | currentPattern;
			break;
		case STATE_MLKC:
			newPattern = LED_04 | currentPattern;
			break;
		default:
			break;
	}
#ifdef X86
	k2k_X86IO_WriteLed(IO->x86IO, newPattern);
#else	
	k2k_IO_WriteLed(IO, newPattern);	
#endif
}

/*!
//
// Do some light show with the LEDs
//
// \param IO is the pointer to the IO structure
// \param direction is 0 for r2l and >0 for l2r
// \param loops is how many loops
// \param speed is how fast to move the LEDs (higher values ==> slower)
// 
// \return nothing
//
*/
void k2k_IO_LightShow(k2k_IO *IO, UINT8 direction, int loops, int speed)
{
	int i;
	UINT8 iPattern = 0;	
	if (direction)
	{		
		/*! run a bit from right to left */		
		for (i = 0; i < loops * 8; i++)
		{			
			iPattern = (iPattern == 0 ? 1 : iPattern << 1);
			k2k_IO_WriteLed(IO, iPattern);
			usleep(speed);
		}	
	}
	else
	{
		/*! run a bit from left to right */
		for (i = 0; i < loops * 8; i++)
		{			
			iPattern = (iPattern == 0 ? 0x80 : iPattern >> 1);
			k2k_IO_WriteLed(IO, iPattern);
			usleep(speed);
		}
	}
	k2k_IO_WriteLed(IO, 0);
}

/*!
//
// Do some random light show with the LEDs
//
// \param IO is the pointer to the IO structure
// \param loops is how many loops
// \param speed is how fast to move the LEDs (higher values ==> slower)
// 
// \return nothing
//
*/
void k2k_IO_RandomLightShow(k2k_IO *IO)
{
	int iPattern = rand();
	k2k_IO_WriteLed(IO, iPattern);
}

